#pragma once
#include <memory>
#include <ThreadPool.h>
#include "cpr/cpr.h"
#include "CommonUtil.h"
//#include "BaseResponse.pb.h"

struct __req_flag {};

typedef std::shared_ptr< __req_flag>    req_flag_ptr;
typedef std::weak_ptr< __req_flag>      req_flag_weak_ptr;

typedef std::function<void(int errCode, const std::string &errMsg, const std::string &content)> HttpCallback;
typedef std::shared_ptr<cpr::Session> SesstionPtr;

class XResponse;
typedef std::shared_ptr<XResponse> XResponsePtr;
typedef std::function<void(const XResponse &resp)> HttpResponse;

class XResponse {
  public:
    XResponse(uint64_t reqId, req_flag_weak_ptr flag, HttpResponse callback);
    XResponse();
    ~XResponse();
    
  public:
    int GetErrorCode()const;
    bool isOK() const;
    bool needReq() const;
    
    std::string GetErrorType() const;
    std::string GetErrorMsg() const;
    
    std::string getHash()const;
    uint64_t    GetReqId()const;
    
    void SetResponse(const cpr::Response &resp);
    void SetReqInfo(uint64_t reqId, req_flag_weak_ptr flag, HttpResponse callback);
    
    void DoCallback()const;
    
    cpr::Response   getRawResponse()const;
    
    Json::Value     getJson()const;
    
  protected:
    uint64_t            m_ReqId;
    cpr::Response       m_rawResponse;
    HttpResponse        m_callback;
    req_flag_weak_ptr   m_flag;
    std::string         m_hash;
};

class HttpClient {
  public:
    static req_flag_ptr create_req_flag();
    
  public:
    HttpClient ();
    ~HttpClient ();
    
  public:
    void Init(HWND hWnd);
    
  public:
    void Post(const std::string &protoId, req_flag_weak_ptr flag,
              const Json::Value &msg,
              HttpResponse callback);
              
    void Get(const std::string &url, req_flag_weak_ptr flag,  HttpResponse callback);
    
    void Process();
  private:
    void PostToServer(const std::string &url, const std::string &msgBuf,
                      XResponsePtr  resp, uint32_t timeout);
                      
    XResponsePtr GetResponsePtr(req_flag_weak_ptr flag, HttpResponse callback, bool inorgeLogin);
    
  private:
    struct TempRequest {
        req_flag_weak_ptr   flag;
        HttpCallback        callback;
        std::string         body;
        int                 code;
        uint32_t            reqId;
    };
    
    std::shared_ptr<cpr::Session> getSession();
    void saveSession(std::shared_ptr<cpr::Session> pSession);
    
  private:
    ThreadPool m_threadPool;
    std::string m_host;
    
    std::mutex                  m_mtx_session;
    std::deque< SesstionPtr>    m_sessions;
    
    std::mutex                  m_mutex;
    std::vector<XResponsePtr>   m_responses;
    cpr::Proxies                m_proxies;
    
    HWND                        m_hWnd;
};

HttpClient &getHttpClient();

#define xHttpClient getHttpClient()